// -----------------------------------------------------------------------------
// This source file is part of Matrix Platform
// 	(Universal .NET Software Development Platform)
// For the latest info, see http://www.matrixplatform.com
// 
// Copyright (c) 2009-2010, Ingenious Ltd
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.Serialization;
using Matrix.Common.Diagnostics;

namespace Matrix.Common.Extended.Operations
{
    /// <summary>
    /// Base class for operations.
    /// </summary>
    [Serializable]
    public class OperationInformation : IDeserializationCallback
    {
        [NonSerialized]
        AutoResetEvent _event;
        public AutoResetEvent CompletionEvent
        {
            get { return _event; }
        }

        volatile string _id = string.Empty;
        /// <summary>
        /// Id of the operation.
        /// </summary>
        public string Id
        {
            get { return _id; }
            set { _id = value; }
        }

        [NonSerialized]
        protected volatile object _response = null;
        public virtual object Response
        {
            get { return _response; }
        }

        [NonSerialized]
        private volatile object _request = null;
        public object Request
        {
            get { return _request; }
            set { _request = value; }
        }

        [NonSerialized]
        volatile bool _isStarted = false;
        /// <summary>
        /// 
        /// </summary>
        public bool IsStarted
        {
            get { return _isStarted; }
        }

        [NonSerialized]
        volatile bool _isComplete = false;

        public delegate void OperationUpdateDelegate(OperationInformation operation);
        [field:NonSerialized]
        public event OperationUpdateDelegate OperationCompleteEvent;

        /// <summary>
        /// Construction.
        /// </summary>
        void Construct()
        {
            _event = new AutoResetEvent(false);

            _response = null;
            _request = null;
            _isStarted = false;
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public OperationInformation()
        {
            Construct();
        }

        public void OnDeserialization(object sender)
        {
            Construct();
        }

        /// <summary>
        /// Wait for operation to finish, a given timeout period.
        /// </summary>
        public bool WaitResult<ExpectedResultType>(TimeSpan timeout, out ExpectedResultType result)
            where ExpectedResultType : class
        {
            lock (this)
            {
                if (_response != null)
                {
                    result = (ExpectedResultType)_response;
                    return true;
                }
            }

            result = null;
            if (timeout == TimeSpan.MaxValue)
            {
                if (_event.WaitOne(-1, true))
                {// Result properly received in assigned time frame.
                    result = (ExpectedResultType)_response;
                    return true;
                }
            }
            else
            {
                if (_event.WaitOne((int)timeout.TotalMilliseconds, true))
                {// Result properly received in assigned time frame.
                    result = (ExpectedResultType)_response;
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        public virtual bool Start()
        {
            lock (this)
            {
                if (_isStarted)
                {
                    SystemMonitor.Error("Operation already complete.");
                    return false;
                }

                _isStarted = true;
            }

            return true;
        }

        /// <summary>
        /// Complete the operation and set the result.
        /// </summary>
        public virtual void Complete(object response)
        {
            lock (this)
            {
                if (_isComplete)
                {
                    SystemMonitor.Error("Operation already complete.");
                    return;
                }

                _isComplete = true;
                _response = response;
                _event.Set();
            }

            if (OperationCompleteEvent != null)
            {
                OperationCompleteEvent(this);
            }
        }


    }
}
